//	Win32 Memory Allocation
////////////////////////////////////////////////////////////////////////////////////////////////////
//#include "stdafx.h"

#include <stdlib.h>
#include <assert.h>
#include <malloc.h>
#include <memory.h>
#include <stdio.h>

#include "Commons.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
void CheckHeap();
void CheckTestBytes();

int GetTotalMemory(int nHeapID)	{ return 0; }
int GetFreeMemory(int nHeapID)	{ return 0; }

////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef MEMORY_DEBUG	

static int ptr_number					=	0;
static int ptr_full						=	0;
static int ptr_max						=	0;
static int ptr_number_max				=	0;
static void* ptr_ptr[MAX_PTR]			=	{0};
static unsigned int ptr_size[MAX_PTR]	=	{0};

#endif	//MEMORY_DEBUG

////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef MEMORY_DEBUG	

int		GetCrtAllocatedPointers()		{ return ptr_number; }
int		GetCrtAllocatedMemory()			{ return ptr_full; }

#else

int		GetCrtAllocatedPointers()		{ return 0; }
int		GetCrtAllocatedMemory()			{ return 0; }

#endif
////////////////////////////////////////////////////////////////////////////////////////////////////

int GetAllocatedHeapSize()
{
#ifdef MEMORY_DEBUG
	return ptr_full;
#else
	return 0;
#endif
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void PrintMemoryStats()
{
#ifdef MEMORY_DEBUG	

	DEBUG_OUT("\n");
	DEBUG_OUT("Memory stats:\n");
	DEBUG_OUT("\tptr_number = %d\n", ptr_number);
	DEBUG_OUT("\tptr_full = %d\n", ptr_full);
	DEBUG_OUT("\tptr_alloc_size = %d\n", ptr_max);
	DEBUG_OUT("\tptr_number_max = %d\n", ptr_number_max);
	// Display still allocated pointers...
	int counter = 10; // only first 10 pointers
	for (int i = 0; i < MAX_PTR; i++)
	{
		if (ptr_ptr[i])
		{
			counter--;
			if (counter <= 0)
			{
				DEBUG_OUT("\t\t...\n");
				break;
			}
			DEBUG_OUT("\t\tptr_index = %5d, ptr_size = %6d, ptr_adr = 0x%08x\n", i, ptr_size[i], (unsigned int)ptr_ptr[i]);
		}
	}

	DEBUG_OUT("\n");

#endif
}

////////////////////////////////////////////////////////////////////////////////////////////////////
void* operator new(unsigned int size)
{
	assert(size != 0);

#ifdef MEMORY_DEBUG	

	void* ptr = malloc(size + 4);
	if (ptr == NULL)
		return NULL;

	memset(ptr, 0, size);

	{
		// put the test values
		unsigned char* ptrU = ((unsigned char*)ptr) + size;
		*ptrU++ = 0x78;
		*ptrU++ = 0x56;
		*ptrU++ = 0x34;
		*ptrU++ = 0x12;
	}

	// search for a free entry
	int i = 0;
	while ((i < MAX_PTR) && (ptr_ptr[i])) i++;
	if (i < MAX_PTR)
	{
		ptr_ptr[i]	=	ptr;
		ptr_size[i] =	size;

		ptr_full += size;
		if (ptr_full > ptr_max)
			ptr_max = ptr_full;
		ptr_number++;
	}

	if (
		( i == 3 && size == 4 )	 ||
		( i == 9 && size == 80 )	 ||
		( i == 13 && size == 80 )	 ||
		( i == 14 && size == 2164 )	 ||
		( i == 15 && size == 28 )
		)
	{
		int tt = 0;
	}

	ptr_number_max++;

#else //MEMORY_DEBUG

	void* ptr = malloc(size);

	if (ptr == NULL)
		return NULL;

	memset(ptr, 0, size);

#endif //MEMORY_DEBUG

	return ptr;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void * operator new[]( unsigned int cb )
{
	void *res = operator new(cb);

	return res;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void operator delete(void *ptr)
{
#ifdef MEMORY_DEBUG

	// search for a free entry
	if (ptr != NULL )
	{
		int i = 0;
		while ((i < MAX_PTR) && (ptr_ptr[i] != ptr)) i++;

		if (i < MAX_PTR)
		{
#ifdef MEMORY_CHECK		
			CheckHeap();
			CheckTestBytes();
#endif //MEMORY_CHECK
			ptr_ptr[i] = NULL;
			ptr_full -= ptr_size[i];
			ptr_size[i] = 0;
			ptr_number--;
		}
	}

#endif //MEMORY_DEBUG

	//ptr = (void*)((char*)ptr - 32);

	free(ptr);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void operator delete[]( void * p )
{
	operator delete(p);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void CheckHeap()
{
#ifdef MEMORY_DEBUG	

	_HEAPINFO hinfo;
	int heapstatus;
	hinfo._pentry = NULL;
	while( ( heapstatus = _heapwalk( &hinfo ) ) == _HEAPOK )
	{
	}

	if (heapstatus != _HEAPEND)
	{
		DEBUG_OUT( "%6s block at %Fp of size %4.4X\n", ( hinfo._useflag == _USEDENTRY ? "USED" : "FREE" ), hinfo._pentry, hinfo._size);
	}

#endif	//MEMORY_DEBUG
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void CheckTestBytes()
{
#ifdef MEMORY_DEBUG	

	for (int i = 0; i < MAX_PTR; i++)
	{
		if (ptr_ptr[i] == NULL)
			continue;

		unsigned char* ptrU = ((unsigned char*)ptr_ptr[i]) + ptr_size[i];

		if ((ptrU[0] != 0x78) ||
			(ptrU[1] != 0x56) ||
			(ptrU[2] != 0x34) ||
			(ptrU[3] != 0x12))
		{
			// ERROR: Buffer overflow!
			DEBUG_OUT( " assert %d , %d" , i , ptr_size[i]);
			GX_ASSERT(0 && "buffer OVERFLOW !");
		}
	}

#endif
}

////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////